package cc.mrbird.febs.utils;

import cc.mrbird.febs.accounting.dto.standardSub.ExportFlagDTO;
import cc.mrbird.febs.accounting.dto.standardSub.SingleExportDTO;
import cc.mrbird.febs.accounting.entity.DetailCost;
import cc.mrbird.febs.accounting.service.impl.CompanyProjectServiceImpl;
import cc.mrbird.febs.accounting.service.impl.DetailCostServiceImpl;
import cc.mrbird.febs.common.utils.FebsUtil;
import cc.mrbird.febs.system.entity.Role;
import cc.mrbird.febs.system.mapper.RoleMapper;
import io.swagger.models.auth.In;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

@Component
public class DetailCostUtil {

    @Resource
    private  CompanyProjectServiceImpl companyProjectService;
    @Resource
    private RoleMapper roleMapper;
    @Resource
    private DetailCostServiceImpl detailCostService;

    // 根据主表明细和分表明细code和时间来合并金额和remark
    public static List<SingleExportDTO> mergeSingleExportDTOs(List<SingleExportDTO> singleExportDTOS) {
        return singleExportDTOS.stream()
                .collect(Collectors.groupingBy(
                        dto -> {
                            Map<String, Object> keyMap = new HashMap<>();
                            keyMap.put("mainCode", dto.getMainCode());
                            keyMap.put("subCode", dto.getSubCode());
                            keyMap.put("yearMonth", dto.getYearMonth());
                            return keyMap;
                        },
                        Collectors.reducing((left, right) -> {
                            if (left.getEstimate() == null) left.setEstimate(0);
                            if (right.getEstimate() == null) right.setEstimate(0);
                            //  如果是项目年终预提标准、节假日福利标准，则不相加，取其中有的值就好
                            if (left.getSubCode().equals(CodeConstant.yearEndAccrualStandardCode) || left.getSubCode().equals(CodeConstant.otherWelfareStandardCode)) {
                                BigDecimal standard = !Objects.equals(left.getCost(), BigDecimal.ZERO) ? left.getCost() : right.getCost();
                                left.setCost(standard);
                                right.setCost(BigDecimal.ZERO);
                            }

                            SingleExportDTO merged = SingleExportDTO.builder()
                                    .projectId(left.getProjectId())
                                    .mainCode(left.getMainCode())
                                    .mainName(left.getMainName())
                                    .subCode(left.getSubCode())
                                    .subName(left.getSubName())
                                    .yearMonth(left.getYearMonth())
                                    .cost(left.getCost().add(right.getCost()))
                                    .estimate(left.getEstimate() + right.getEstimate() >= 1 ? 1 : 0)
                                    .remark(mergeRemark(left.getRemark(), right.getRemark()))
                                    .build();
                            return merged;
                        })
                ))
                .values()
                .stream()
                .map(optional -> optional.orElse(new SingleExportDTO()))
                .collect(Collectors.toList());
    }

    public static List<DetailCost> mergeDetailCost (List<DetailCost> detailCosts) {
        return detailCosts.stream()
                .collect(Collectors.groupingBy(
                        detailCost -> {
                            Map<String, Object> keyMap = new HashMap<>();
                            keyMap.put("detailSubjectCode", detailCost.getDetailSubjectCode());
                            keyMap.put("yearMonth", detailCost.getYearMonth());
                            return keyMap;
                        },
                        Collectors.reducing((left, right) -> {
                            if (left.getEstimate() == null) left.setEstimate(0);
                            if (right.getEstimate() == null) right.setEstimate(0);
                            DetailCost merged = DetailCost.builder()
                                    .detailSubjectCode(left.getDetailSubjectCode())
                                    .yearMonth(left.getYearMonth())
                                    .cost(left.getCost().add(right.getCost()))
                                    .estimate(left.getEstimate() + right.getEstimate() >= 1 ? 1 : 0)
                                    .remark(mergeRemark(left.getRemark(), right.getRemark()))
                                    .type(left.getType())
                                    .build();
                            return merged;
                        })
                ))
                .values()
                .stream()
                .map(optional -> optional.orElse(new DetailCost()))
                .collect(Collectors.toList());
    }

    private static String mergeRemark(String leftRemark, String rightRemark) {
        StringBuilder sb = new StringBuilder();
        if (leftRemark!= null) {
            sb.append(leftRemark);
        }
        if (rightRemark!= null) {
            if (sb.length() > 0) {
                sb.append("\n");
            }
            sb.append(rightRemark);
        }
        return sb.toString();
    }


    // 根据角色信息和项目id获取对于公司id
    public List<Long> getCompanyIds4pro(Long projectId) {
        List<Long> companyIds = companyProjectService.getCompanyIdsByPid(projectId);
        // 根据角色权限只获取对应公司的项目权限
        Role role = roleMapper.selectById(FebsUtil.getCurrentUser().getRoleId());
        if (role.getPermissionType() == 0 && !Objects.equals(role.getRoleId(), CommonConstant.HZTT_ROLE_ID)) {
            List<String> hasPer = Arrays.asList(role.getCompanyPermission().split(","));
            List<Long> realPer = new ArrayList<>();
            for (Long companyId : companyIds) {
                if (hasPer.contains(companyId.toString())) {
                    realPer.add(companyId);
                }
            }
            companyIds = realPer;
        }
        return companyIds;
    }

    public ExportFlagDTO getMergedSingleExport(Long projectId, String year, List<String> yearMonths) {
        List<Long> companyIds = getCompanyIds4pro(projectId);

        ExportFlagDTO exportFlagDTO = new ExportFlagDTO().setFlag(0).setInsuranceError(false);
        List<SingleExportDTO> rawList = new ArrayList<>();
        for (Long companyId : companyIds) {
            ExportFlagDTO dto = detailCostService.queryDetailForExcel(companyId, projectId, year, yearMonths);
            // 保存每个项目的数据
            rawList.addAll(dto.getSingleExportDTOS());
            // 更新标志值
            if (dto.getFlag() == 1) {
                exportFlagDTO.setFlag(dto.getFlag());
            }
            if (dto.getInsuranceError()) {
                exportFlagDTO.setInsuranceError(dto.getInsuranceError());
            }
        }
        // 对不同公司的项目数据按照项目进行合并
        List<SingleExportDTO> mergedList = DetailCostUtil.mergeSingleExportDTOs(rawList);
        exportFlagDTO.setSingleExportDTOS(mergedList);
        return exportFlagDTO;
    }

    // 合并后直接加存在的问题，重新计算 人均结算收入/总人数 和 人均发放工资
    public List<SingleExportDTO> adjustResult(List<SingleExportDTO> list) {

        // 人均结算收入/总人数
        Map<String, BigDecimal> monthPeople = new HashMap<>();
        Map<String, BigDecimal> selfIncomeCode = new HashMap<>();

        // 重新计算 人均发放工资
        Map<String, BigDecimal> shouldPay = new HashMap<>();
        //  节假日及其他福利标准
        Map<String, BigDecimal> otherWelfareStandardCode = new HashMap<>();
        // 节假日及其他福利
        Map<String, BigDecimal> otherWelfareTmp = new HashMap<>();
        //  项目年终预提标准
        Map<String, BigDecimal> yearEndAccrualStandardCode = new HashMap<>();

        for (SingleExportDTO singleExportDTO : list) {
            if (singleExportDTO.getSubCode().equals(CodeConstant.monthPeople)) {
                monthPeople.put(singleExportDTO.getYearMonth(), singleExportDTO.getCost());
            }
            if (singleExportDTO.getSubCode().equals(CodeConstant.selfIncomeCode)) {
                selfIncomeCode.put(singleExportDTO.getYearMonth(), singleExportDTO.getCost());
            }
            if (singleExportDTO.getSubCode().equals(CodeConstant.shouldPay)) {
                shouldPay.put(singleExportDTO.getYearMonth(), singleExportDTO.getCost());
            }
            if (singleExportDTO.getSubCode().equals(CodeConstant.otherWelfareStandardCode)) {
                otherWelfareStandardCode.put(singleExportDTO.getYearMonth(), singleExportDTO.getCost());
            }
            if (singleExportDTO.getSubCode().equals(CodeConstant.otherWelfareTmp)) {
                otherWelfareTmp.put(singleExportDTO.getYearMonth(), singleExportDTO.getCost());
            }
            if (singleExportDTO.getSubCode().equals(CodeConstant.yearEndAccrualStandardCode)) {
                yearEndAccrualStandardCode.put(singleExportDTO.getYearMonth(), singleExportDTO.getCost());
            }
        }

        for (Map.Entry<String, BigDecimal> entry : monthPeople.entrySet()) {
            if (entry.getValue().equals(BigDecimal.ZERO)) continue;
            String yearMonth = entry.getKey();
            // 重新计算 人均结算收入/总人数
            BigDecimal pAvgIncome = selfIncomeCode.getOrDefault(yearMonth, BigDecimal.ZERO).divide(entry.getValue(), 2, RoundingMode.HALF_UP);
            // 重新计算 人均发放工资
            BigDecimal pAvgWage = shouldPay.getOrDefault(yearMonth, BigDecimal.ZERO).divide(entry.getValue(), 2, RoundingMode.HALF_UP);
            // 重新计算 节假日福利及开门红包预提
            BigDecimal otherWelfare = entry.getValue().multiply(otherWelfareStandardCode.getOrDefault(yearMonth, BigDecimal.ZERO)).subtract(otherWelfareTmp.getOrDefault(yearMonth, BigDecimal.ZERO));
            // 重新计算 项目年终预提
            BigDecimal annualBonus = yearEndAccrualStandardCode.getOrDefault(yearMonth, BigDecimal.ZERO).multiply(entry.getValue());

            //  重新赋值
            for (SingleExportDTO singleExportDTO : list) {
                if (singleExportDTO.getSubCode().equals(CodeConstant.pAvgIncome) && singleExportDTO.getYearMonth().equals(yearMonth)) {
                    singleExportDTO.setCost(pAvgIncome);
                }
                if (singleExportDTO.getSubCode().equals(CodeConstant.pAvgWage) && singleExportDTO.getYearMonth().equals(yearMonth)) {
                    singleExportDTO.setCost(pAvgWage);
                }
                if (singleExportDTO.getSubCode().equals(CodeConstant.otherWelfare) && singleExportDTO.getYearMonth().equals(yearMonth)) {
                    singleExportDTO.setCost(otherWelfare);
                }
                if (singleExportDTO.getSubCode().equals(CodeConstant.annualBonus) && singleExportDTO.getYearMonth().equals(yearMonth)) {
                    singleExportDTO.setCost(annualBonus);
                }
            }
        }

        return list;
    }
}

